package com.fuhailiu.opengl.widget;

import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;

import javax.microedition.khronos.opengles.GL10;

import android.content.Context;
import android.opengl.GLES30;

import com.fuhailiu.opengl.utils.GlUtil;
import com.fuhailiu.opengl.utils.LogUtil;
import com.fuhailiu.opengl.utils.MatrixUtil;
import com.fuhailiu.opengl.utils.ShaderUtil;
import com.fuhailiu.opengl.view.GLView;

public class GLPolygonOffset extends GLView {

	private final String TAG = getClass().getSimpleName();

	// 顶点坐标数据缓冲
	private FloatBuffer mBufferVertex;

	// 自定义渲染管线程序id
	private int handleProgram;
	// 顶点位置属性引用id
	private int handlePosition;
	// 顶点颜色属性引用id
	private int handleColor;
	// 总变换矩阵引用id
	private int handleMVPMatrix;
	// 顶点个数
	private int mVertexCount;

	public GLPolygonOffset(Context context, float radius, int sectionNumber) {
		super(context);
		initVertexData(radius, sectionNumber);
		initShader();
	}

	private void initVertexData(float radius, int sectionNumber) {
		List<Float> list = new ArrayList<Float>();

		// center point
		list.add(0f);
		list.add(0f);
		list.add(0f);

		float angleStep = 360 / sectionNumber;
		for (float angle = 0; angle < 360; angle += angleStep) {
			float x = (float) (radius * Math.cos(Math.toRadians(angle)));
			float y = (float) (radius * Math.sin(Math.toRadians(angle)));
			list.add(x);
			list.add(y);
			list.add(0f);
		}

		// Close the circle
		list.add(list.get(3));
		list.add(list.get(4));
		list.add(list.get(5));

		mVertexCount = list.size() / 3;

		// vertex
		float[] vertexArray = new float[mVertexCount * 3];
		for (int i = 0; i < mVertexCount; i++) {
			vertexArray[i * 3] = list.get(i * 3);
			vertexArray[i * 3 + 1] = list.get(i * 3 + 1);
			vertexArray[i * 3 + 2] = list.get(i * 3 + 2);
		}
		mBufferVertex = GlUtil.createFloatBuffer(vertexArray);
	}

	private static final String VERTEX_SHADER = 
			"uniform mat4 uMVPMatrix; //总变换矩阵\n" + 
			"attribute vec3 aPosition; //顶点位置\n" + 
			"uniform vec4 aColor; //顶点颜色\n" + 
			"varying vec4 vColor; //用于传递给片元着色器的变量\n" + 
			"void main()\n" + 
			"{\n" + 
			"	gl_Position = uMVPMatrix * vec4(aPosition,1); //根据总变换矩阵计算此次绘制此顶点位置\n" + 
			"	vColor = aColor; //将接收的颜色传递给片元着色器 \n" + 
			"}\n";

	private static final String FRAGMENT_SHADER = 
			"precision mediump float;\n" + 
			"varying vec4 vColor; //接收从顶点着色器过来的参数\n" + 
			"void main()\n" + 
			"{\n" + 
			"	gl_FragColor = vColor; //给此片元颜色值\n" + 
			"}\n";

	private void initShader() {
		LogUtil.LogD(TAG, "initShader   <---");

		// 基于顶点着色器与片元着色器创建程序
		handleProgram = ShaderUtil.createProgram(VERTEX_SHADER, FRAGMENT_SHADER);
		// 获取程序中顶点位置属性引用id
		handlePosition = GLES30.glGetAttribLocation(handleProgram, "aPosition");
		// 获取程序中顶点颜色属性引用id
		handleColor = GLES30.glGetUniformLocation(handleProgram, "aColor");
		// 获取程序中总变换矩阵引用id
		handleMVPMatrix = GLES30.glGetUniformLocation(handleProgram, "uMVPMatrix");

		LogUtil.LogD(TAG, "initShader   --->");
	}

	public static final int OFFSET_OFF = 0;
	public static final int OFFSET_ON = 1;

	private int mOffsetMode = OFFSET_ON;

	// Depth Offset = DZ * factor + r * units
	// DZ为深度值（z值）相对于多边形屏幕区域的变化量
	// r是使深度缓冲区值产生变化的最小值
	// 负值将使z值距离我们更近

	public void setOffsetMode(int mode) {
		mOffsetMode = mode;
		LogUtil.LogD(TAG, "setOffsetMode mode = " + mode);
	}

	public volatile float mTranslateX = 0;
	public volatile float mTranslateY = 0;

	private final float red[] = { 1.0f, 0.0f, 0.0f, 1.0f };
	private final float green[] = { 0.0f, 1.0f, 0.0f, 1.0f };
	private final float blue[] = { 0.0f, 0.0f, 1.0f, 1.0f };

	private final int sizeOfVertexPosition = 3;

	public void draw(GL10 gl) {
		// 使用shader程序
		GLES30.glUseProgram(handleProgram);

		// 启用顶点位置数组
		GLES30.glEnableVertexAttribArray(handlePosition);
		// 启用顶点颜色数组
		GLES30.glEnableVertexAttribArray(handleColor);
		// 指定顶点位置数据
		GLES30.glVertexAttribPointer(handlePosition, sizeOfVertexPosition, GLES30.GL_FLOAT, false, sizeOfVertexPosition * GlUtil.SIZE_OF_FLOAT, mBufferVertex);

		// 画左右圆
		drawCircle(-0.4f, 0, red);
		drawCircle(0.4f, 0, blue);

		// 多边形偏移
		if (mOffsetMode == OFFSET_ON) {
			GLES30.glEnable(GLES30.GL_POLYGON_OFFSET_FILL);
			GLES30.glPolygonOffset(-1.0f, -1.0f);
		}
		// 画中心圆
		drawCircle(mTranslateX, mTranslateY, green);
		// 关闭多边形偏移
		GLES30.glDisable(GLES30.GL_POLYGON_OFFSET_FILL);

		// 禁用顶点位置数组
		GLES30.glDisableVertexAttribArray(handleColor);
		// 禁用顶点颜色数组
		GLES30.glDisableVertexAttribArray(handlePosition);
	}

	private void drawCircle(float translateX, float translateY, float[] color) {
		// 保存当前矩阵
		MatrixUtil.pushMatrix();
		MatrixUtil.translate(translateX, translateY, 0);

		// 指定顶点颜色数据，使用单调着色
		GLES30.glUniform4fv(handleColor, 1, color, 0);

		// 指定变换矩阵
		GLES30.glUniformMatrix4fv(handleMVPMatrix, 1, false, MatrixUtil.getMVPMatrix(), 0);

		// 绘制三角形
		GLES30.glDrawArrays(GLES30.GL_TRIANGLE_FAN, 0, mVertexCount);

		// 恢复矩阵
		MatrixUtil.popMatrix();
	}

}
